package com.chuxing.system.service.impl;

import cn.dev33.satoken.stp.StpUtil;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.chuxing.config.GroupRole;
import com.chuxing.config.PermissionsState;
import com.chuxing.config.SecurityRole;
import com.chuxing.domain.ClassInfo;
import com.chuxing.domain.DTO.AddGroupMembersByAdminDTO;
import com.chuxing.domain.DTO.NotGroupMembersDTO;
import com.chuxing.domain.DTO.TClassListMembersDTO;
import com.chuxing.domain.DTO.TGroupMembersListDTO;
import com.chuxing.domain.TClassMembers;
import com.chuxing.domain.TGroupMembers;
import com.chuxing.domain.TGroups;
import com.chuxing.domain.VO.PageResultVO;
import com.chuxing.domain.VO.TGroupmembersListVO;
import com.chuxing.exception.GenericException;
import com.chuxing.exception.UnauthorizedException;
import com.chuxing.system.mapper.ClassinfoMapper;
import com.chuxing.system.mapper.TGroupMembersMapper;
import com.chuxing.system.mapper.TGroupsMapper;
import com.chuxing.system.service.ITClassMembersService;
import com.chuxing.system.service.ITGroupMembersService;
import com.chuxing.system.service.ITGroupsService;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import jakarta.servlet.http.HttpServletResponse;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.springframework.beans.BeanUtils;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.io.IOException;
import java.io.InputStream;
import java.time.LocalDate;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;

/**
 * 小组成员Service业务层处理
 * 
 * @author 刘祺
 * @date 2025-01-11
 */
@Service
@Slf4j
@Transactional
@RequiredArgsConstructor
public class TGroupMembersServiceImpl extends ServiceImpl<TGroupMembersMapper, TGroupMembers> implements ITGroupMembersService

{
    private final TGroupMembersMapper tGroupMembersMapper;
    private final ITClassMembersService iTClassMembersService;
    private final ITGroupsService iTGroupsService;
    private final TGroupsMapper tGroupsMapper;
    private final ClassinfoMapper classinfoMapper;


    /**
     * 查询小组成员
     * 
     * @param GroupMemberID 小组成员主键
     * @return 小组成员
     */
    @Override
    public TGroupMembers selectTGroupmembersByGroupMemberID(Long GroupMemberID)
    {
        return tGroupMembersMapper.selectTGroupmembersByGroupMemberID(GroupMemberID);
    }

    /**
     * 查询小组成员列表
     *
     * @return 小组成员
     */
    @Override
    @Cacheable(value = "tGroupMembersList", key = "#tGroupMembersListDTO")
    public PageResultVO selectTGroupmembersList(TGroupMembersListDTO tGroupMembersListDTO)
    {
        // 验证分页参数
        if(tGroupMembersListDTO.getClassID()==null||tGroupMembersListDTO.getGroupID()==null){
            // 判断是否为管理员
            if(!StpUtil.hasRole(SecurityRole.ROLE_ADMIN)){
                throw new UnauthorizedException(PermissionsState.PERMISSION_NOT_ENOUGH);
            }
        }
        // 验证分页参数
        int pageNum = Math.max(1, tGroupMembersListDTO.getPageNum());
        int pageSize = Math.max(1, tGroupMembersListDTO.getPageSize());
        // 启用分页查询
        PageHelper.startPage(pageNum, pageSize);
        try {
            try (Page<TGroupMembers> page = tGroupMembersMapper.selectTGroupmembersList(tGroupMembersListDTO)) {
                // 构造并返回分页结果对象
                List<TGroupMembers> result = page.getResult();
                List<TGroupmembersListVO> list=new ArrayList<>();
                String studentId = StpUtil.getLoginIdAsString();
                // 遍历结果集
                for (TGroupMembers tGroupMembers : result) {
                    TGroupmembersListVO tGroupmembersListVO = new TGroupmembersListVO();
                    BeanUtils.copyProperties(tGroupMembers, tGroupmembersListVO);
                    TClassMembers user = null;
                    user = iTClassMembersService.selectTclassMembersByStudentIdAndTClassInfo(tGroupMembers.getStudentID(),tGroupMembers.getClassID());
                    // 如果班级信息不为空，则将班级信息复制到VO对象中
                    if (user != null) {
                        BeanUtils.copyProperties(user, tGroupmembersListVO);
                    }
                    list.add(tGroupmembersListVO);
                }
                if(!StpUtil.hasRole(SecurityRole.ROLE_ADMIN)){
                    TClassMembers user = iTClassMembersService.selectTclassMembersByStudentIdAndTClassInfo(studentId, tGroupMembersListDTO.getClassID());
                    if(user==null){
                        throw new GenericException("未加入该班级，无法查看");
                    }
                }
                // 构造并返回分页结果对象
                return new PageResultVO(page.getTotal(),list);
            }
        }catch (GenericException e){
            throw e;
        } catch (Exception e) {
            log.error("获取小组成员列表时发生错误", e);
            // 抛出通用异常，不暴露具体错误信息
            throw new GenericException("系统内部错误");
        } finally {
            // 确保分页查询结束
            PageHelper.clearPage();
        }
    }

    /**
     * 新增小组成员
     * 该方法用于向指定小组中添加新成员它创建一个TGroupMembers对象，设置必要的属性，
     * 包括小组ID、加入日期、学生ID和小组内的角色，然后调用Mapper接口的方法将该成员信息插入数据库
     *
     * @return 结果
     */
    @Override
    @CacheEvict(value = "tGroupMembersList", allEntries = true)
    public int insertTGroupmembers(long groupID)
    {
        // 查询小组信息
        TGroups tGroups = iTGroupsService.selectTGroupsByGroupID(groupID);
        if(tGroups==null){
            throw new GenericException("小组不存在");
        }
        //判断学生是否已经加入该班级
        TClassMembers tClassMembers = iTClassMembersService.selectTclassMembersByStudentIdAndTClassInfo(StpUtil.getLoginIdAsString(), tGroups.getClassID());
        if(tClassMembers==null){
            throw new GenericException("未加入班级，禁止加入小组！");
        }
        // 创建新的小组成员对象
        TGroupMembers tGroupmembers = new TGroupMembers();
        // 设置小组ID
        tGroupmembers.setGroupID(groupID);
        // 设置加入日期为当前日期
        tGroupmembers.setJoinDate(LocalDate.now());
        // 设置学生ID为当前登录用户ID
        tGroupmembers.setStudentID(StpUtil.getLoginIdAsString());
        // 设置小组内的角色为小组成员
        tGroupmembers.setRoleInGroup(GroupRole.GROUP_MEMBER);
        // 设置班级ID为小组的班级ID
        tGroupmembers.setClassID(tGroups.getClassID());
        // 查询该学生是否已经加入该小组
        Long count = tGroupMembersMapper.countByStudentAndClass(tGroupmembers.getStudentID(),tGroupmembers.getClassID());
        if (count>0){
            throw new GenericException("已加入小组");
        }
        // 判断小组是否已满
        if(tGroupMembersMapper.countByGroupID(tGroupmembers.getGroupID())>=tGroups.getMaxMembers()){
            throw new GenericException("小组人数已满");
        }

        // 调用Mapper接口的方法插入新的小组成员信息
        return tGroupMembersMapper.insertTGroupmembers(tGroupmembers);
    }

    /**
     * 修改小组成员
     * 
     * @param tGroupmembers 小组成员
     * @return 结果
     */
    @Override
    @CacheEvict(value = "tGroupMembersList", allEntries = true)
    public int updateTGroupmembers(TGroupMembers tGroupmembers)
    {
        TGroups tGroups = iTGroupsService.selectTGroupsByGroupID(tGroupmembers.getGroupID());
        if(tGroups==null){
            throw new GenericException("小组不存在");
        }
        //获取当前小组的人数
        int count =tGroupMembersMapper.countByGroupID(tGroupmembers.getGroupID());
        if(count>=tGroups.getMaxMembers()){
            throw new GenericException("小组人数已满");
        }
        //如果当前账号的身份是组长，则不允许修改
        TGroupMembers tGroupMembers = tGroupMembersMapper.selectTGroupmembersByGroupMemberID(tGroupmembers.getGroupMemberID());
        if (tGroupMembers.getRoleInGroup().equals(GroupRole.GROUP_LEADER)) {
            throw new GenericException("该学生是组长，无法换组！");
        }

        return tGroupMembersMapper.updateTGroupmembers(tGroupmembers);
    }

    /**
     * 批量删除小组成员
     * 
     * @param GroupMemberIDs 需要删除的小组成员主键数组
     * @return 删除操作的结果
     */
    @Override
    @CacheEvict(value = "tGroupMembersList", allEntries = true)
    public int deleteTGroupmembersByGroupMemberIDs(Long[] GroupMemberIDs)
    {
        // 初始化标志变量
        boolean cheekSelf = false, cheekLeader = false;
        // 获取当前登录用户的ID
        String loginIdAsString = StpUtil.getLoginIdAsString();
        // 遍历要删除的小组成员ID数组
        for (Long groupMemberID : GroupMemberIDs) {
            // 根据小组成员ID查询小组成员信息
            TGroupMembers tGroupMembers = selectTGroupmembersByGroupMemberID(groupMemberID);
            // 检查当前操作者是否为小组成员本人
            cheekSelf = tGroupMembers.getStudentID().equals(loginIdAsString);
            // 根据小组ID查询小组信息
            TGroups tGroups = iTGroupsService.selectTGroupsByGroupID(tGroupMembers.getGroupID());
            // 检查当前操作者是否为小组组长
            if(tGroups.getGroupLeaderID()!=null){
                cheekLeader = tGroups.getGroupLeaderID().equals(loginIdAsString);
                //如果被删除的小组成员是组长，则修改小组组长为空
                if(tGroups.getGroupLeaderID().equals(tGroupMembers.getStudentID())){
                    tGroups.setGroupLeaderID(null);
                    iTGroupsService.updateTGroups(tGroups);
                }
            }
        }
        // 判断当前操作者是否为管理员
        if(StpUtil.hasRole(SecurityRole.ROLE_ADMIN)){
            // 如果是管理员，直接执行删除操作
            return tGroupMembersMapper.deleteTGroupmembersByGroupMemberIDs(GroupMemberIDs);
        }
        // 如果当前操作者是自己，允许执行删除操作
        if(cheekSelf){
            return tGroupMembersMapper.deleteTGroupmembersByGroupMemberIDs(GroupMemberIDs);
        }
        // 如果当前操作者是小组组长，允许执行删除操作
        if(cheekLeader){
            return tGroupMembersMapper.deleteTGroupmembersByGroupMemberIDs(GroupMemberIDs);
        }
        // 如果既不是小组成员本人也不是小组组长，则抛出权限不足异常
        throw new UnauthorizedException(PermissionsState.PERMISSION_NOT_ENOUGH);
    }

    /**
     * 选择非小组成员列表
     * 该方法用于获取不属于任何小组的班级成员列表
     *
     * @param notGroupMembersDTO 包含班级ID和学生ID的查询条件对象
     * @return 返回非小组成员的班级成员列表
     */
    @Override
    public List<TClassMembers> selectNotGroupmembersList(NotGroupMembersDTO notGroupMembersDTO) {
        // 查询班级所有小组成员信息
        TGroupMembersListDTO tGroupMembersListDTO = new TGroupMembersListDTO();
        tGroupMembersListDTO.setPageNum(1);
        tGroupMembersListDTO.setPageSize(Integer.MAX_VALUE);
        tGroupMembersListDTO.setClassID(notGroupMembersDTO.getClassID());
        PageResultVO GroupMemberPageResultVO = selectTGroupmembersList(tGroupMembersListDTO);
        List<TGroupmembersListVO> groupMemberPageResultVORecords = GroupMemberPageResultVO.getRecords();

        //查询班级信息
        TClassListMembersDTO tClassListMembersDTO = new TClassListMembersDTO();
        tClassListMembersDTO.setPageNum(1);
        tClassListMembersDTO.setPageSize(Integer.MAX_VALUE);
        tClassListMembersDTO.setStudentId(notGroupMembersDTO.getStudentID());
        tClassListMembersDTO.setClassID(notGroupMembersDTO.getClassID());
        PageResultVO ClassMembersPageResultVO1 = iTClassMembersService.selectTClassList(tClassListMembersDTO);
        List<TClassMembers> classMembersPageResultVORecords = ClassMembersPageResultVO1.getRecords();

        //筛选出非小组成员的班级成员
        ArrayList<TClassMembers> tClassMembers = new ArrayList<>();
        for (TClassMembers i : classMembersPageResultVORecords) {
            //判断是否在小组成员列表中
            boolean flag = true;
            for (TGroupmembersListVO j : groupMemberPageResultVORecords) {
                if(i.getStudentId().equals(j.getStudentID())&&i.getClassID().equals(j.getClassID())){
                    flag = false;
                    break;
                }
            }
            if(flag){
                //将符合条件的班级成员添加到结果列表中
                tClassMembers.add(i);
            }
        }
        return tClassMembers;
    }

    /**
     * 根据学生ID和班级ID添加小组成员
     * 该方法用于根据学生ID和班级ID和小组ID添加小组成员
     *
     * @param addGroupMembersByAdminDTO 包含学生ID和班级ID的DTO对象
     */
    @Override
    @CacheEvict(value = "tGroupMembersList", allEntries = true)
    public void AddGroupMembersByAdmin(AddGroupMembersByAdminDTO addGroupMembersByAdminDTO) {
        TGroups tGroups = iTGroupsService.selectTGroupsByGroupID(addGroupMembersByAdminDTO.getGroupID());
        if(tGroups==null){
            throw new GenericException("小组不存在");
        }
        //获取当前小组的人数
        int count =tGroupMembersMapper.countByGroupID(addGroupMembersByAdminDTO.getGroupID());
        if(count>=tGroups.getMaxMembers()){
            throw new GenericException("小组人数已满");
        }
        Long count1 = tGroupMembersMapper.countByStudentAndClass(addGroupMembersByAdminDTO.getStudentID(), addGroupMembersByAdminDTO.getClassID());
        if(count1>0){
            throw new GenericException("该成员已加入该小组");
        }
        TGroupMembers tGroupMembers = new TGroupMembers();
        BeanUtils.copyProperties(addGroupMembersByAdminDTO,tGroupMembers);
        tGroupMembers.setJoinDate(LocalDate.now());
        // 设置小组内的角色为小组成员
        tGroupMembers.setRoleInGroup(GroupRole.GROUP_MEMBER);
        tGroupMembersMapper.insertTGroupmembers(tGroupMembers);
    }

    @Override
    public void export(HttpServletResponse response, TGroupMembersListDTO tGroupMembersListDTO) {
        try {
            // 获取小组成员信息列表
            PageResultVO list = selectTGroupmembersList(tGroupMembersListDTO);
            // 获取小组成员信息记录列表
            List<TGroupmembersListVO> records = list.getRecords();
            //将小组成员信息按小组号排序
            records.sort(Comparator.comparing(TGroupmembersListVO::getGroupID));
            // 加载小组成员信息模板文件
            InputStream resourceAsStream = this.getClass().getClassLoader().getResourceAsStream("static/小组成员信息.xlsx");
            // 创建Workbook对象用于操作Excel文件
            Workbook workbook = null;
            // 检查是否成功加载模板文件
            if (resourceAsStream != null) {
                workbook = new XSSFWorkbook(resourceAsStream);
            }
            //查询所有班级信息
            List<ClassInfo> classInfoList = classinfoMapper.selectClassinfo();
            HashMap<Long, String> classMap = new HashMap<>();
            for (ClassInfo classInfo : classInfoList) {
                classMap.put(classInfo.getId(),classInfo.getClassName());
            }
            //查询所有小组信息
            List<TGroups> tGroupsList = tGroupsMapper.selectTGroups();
            HashMap<Long, String> groupMap = new HashMap<>();
            for (TGroups tGroups : tGroupsList) {
                groupMap.put(tGroups.getGroupID(),tGroups.getGroupName());
            }
            // 检查Workbook对象是否创建成功
            if (workbook != null) {
                // 获取第一个Sheet页
                Sheet sheet = workbook.getSheetAt(0); //读取
                // 遍历班级成员信息记录并写入Excel
                for (int i = 0; i < records.size(); i++) {
                    // 创建新行
                    Row row = sheet.createRow(i + 1);
                    int j=0;
                    // 写入小组名称
                    row.createCell(j++).setCellValue(groupMap.get(records.get(i).getGroupID()));
                    // 写入小组成员身份
                    row.createCell(j++).setCellValue(records.get(i).getRoleInGroup());
                    // 写入学生ID
                    row.createCell(j++).setCellValue(records.get(i).getStudentID());
                    // 写入学生姓名
                    row.createCell(j++).setCellValue(records.get(i).getStuName());
                    // 写入学生性别
                    row.createCell(j++).setCellValue(records.get(i).getStuSex());
                    // 写入班级名称
                    row.createCell(j++).setCellValue(classMap.get(records.get(i).getClassID()));
                    // 写入学生所在院系
                    row.createCell(j++).setCellValue(records.get(i).getStuDepartment());
                    // 写入学生专业
                    row.createCell(j++).setCellValue(records.get(i).getStuSpeciality());
                    // 写入学生班级
                    row.createCell(j++).setCellValue(records.get(i).getStuClass());
                    // 写入学生年级
                    row.createCell(j++).setCellValue(records.get(i).getStuGrade());
                    // 写入学生邮箱
                    row.createCell(j++).setCellValue(records.get(i).getEmail());
                    // 写入学生电话
                    row.createCell(j++).setCellValue(records.get(i).getStuPhone());
                }
                // 将Excel数据写入HTTP响应流
                workbook.write(response.getOutputStream());
                // 关闭Workbook对象
                workbook.close();
                // 关闭输入流
                resourceAsStream.close();
                // 刷新HTTP响应流
                response.getOutputStream().flush();
                // 关闭HTTP响应流
                response.getOutputStream().close();
                log.info("管理员导出小组成员信息列表成功");
            }
        }catch (IOException e) {
            throw new GenericException("导出小组成员信息列表失败");
        }
    }
}
